#region --- License & Copyright Notice ---
/*
ConsoleFx CommandLine Processing Library

Copyright (c) 2006-2012 Jeevan James
All rights reserved.

The contents of this file are made available under the terms of the
Eclipse Public License v1.0 (the "License") which accompanies this
distribution, and is available at the following URL:
http://opensource.org/licenses/eclipse-1.0.txt

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

By using this software in any fashion, you are agreeing to be bound by the
terms of the License.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;

using ConsoleFx.Resources;

namespace ConsoleFx.Parsers
{
    [DebuggerDisplay("{Requirement} | Parameters: {MinParameters} - {MaxParameters}")]
    public sealed class OptionUsage
    {
        private int _minOccurences;
        private int _maxOccurences = 1;
        private int _minParameters;
        private int _maxParameters;

        public OptionUsage()
        {
            //By default, option is optional... can be omitted or appear exactly once
            MinOccurences = 0;
            MaxOccurences = 1;

            //By default, parameters are not allowed on an option
            MinParameters = 0;
            MaxParameters = 0;

            ParameterType = OptionParameterType.Individual;
        }

        public int MaxOccurences
        {
            get { return _maxOccurences; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value", ParserMessages.OccurenceParameterValueNegative);
                _maxOccurences = value;
            }
        }

        public int MinOccurences
        {
            get { return _minOccurences; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value", ParserMessages.OccurenceParameterValueNegative);
                _minOccurences = value;
            }
        }

        public int MaxParameters
        {
            get { return _maxParameters; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value", ParserMessages.OccurenceParameterValueNegative);
                _maxParameters = value;
            }
        }

        public int MinParameters
        {
            get { return _minParameters; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value", ParserMessages.OccurenceParameterValueNegative);
                _minParameters = value;
            }
        }

        public int? ExpectedOccurences
        {
            get { return MinOccurences == MaxOccurences ? MinOccurences : (int?)null; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value", ParserMessages.OccurenceParameterValueNegative);
                _minOccurences = value.GetValueOrDefault(0);
                _maxOccurences = value.GetValueOrDefault(1);
            }
        }

        public int? ExpectedParameters
        {
            get { return MinParameters == MaxParameters ? MinParameters : (int?)null; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value", ParserMessages.OccurenceParameterValueNegative);
                _minParameters = value.GetValueOrDefault(0);
                _maxParameters = value.GetValueOrDefault(0);
            }
        }

        public OptionRequirement Requirement
        {
            get
            {
                if (MaxOccurences > 0)
                    return MinOccurences > 0 ? OptionRequirement.Required : OptionRequirement.Optional;
                return OptionRequirement.NotAllowed;
            }
            set
            {
                switch (value)
                {
                    case OptionRequirement.Optional:
                        _minOccurences = 0;
                        if (_maxOccurences == 0)
                            _maxOccurences = 1;
                        break;
                    case OptionRequirement.Required:
                        _minOccurences = 1;
                        if (_maxOccurences == 0)
                            _maxOccurences = 1;
                        break;
                    case OptionRequirement.NotAllowed:
                        _minOccurences = _maxOccurences = 0;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException("value");
                }
            }
        }

        public OptionParameterType ParameterType { get; set; }
    }

    [Serializable]
    public sealed class OptionUsages : Dictionary<string, OptionUsage>
    {
        public OptionUsages()
        {
        }

        private OptionUsages(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }

        public new OptionUsage this[string context]
        {
            get
            {
                OptionUsage usage;
                if (TryGetValue(context, out usage))
                    return usage;
                usage = new OptionUsage();
                Add(context, usage);
                return usage;
            }
        }
    }
}